package com.future.common.base;

import java.util.List;
import java.util.Map;

import com.future.common.global.PlatFormContext;
import com.jfinal.aop.Aop;
import com.jfinal.plugin.activerecord.DbKit;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.SqlPara;
import com.jfinal.plugin.activerecord.cache.ICache;

import cn.hutool.core.util.ClassUtil;

/**
 * Dao类的基类，继承此类后能简化Dao层的代码 例如 Dao中的代码是 package com.test; public class User{
 * public SysUser getUser(String username){ return find(username); } }
 * find(username)会去找key为 com.test.getUser的sql模板执行
 *
 *
 * Model类型
 * 
 * @param <T>
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public class BaseDao<T extends Model<T>> {
	/**
	 * 获取model对象，此处不用DB是因为DB会在主数据源中查找sql,不适合多数据源的情况
	 */
	private T t = (T) Aop.get(ClassUtil.getTypeArgument(
			getClass().getName().indexOf("$$EnhancerBy") == -1 ? getClass() : getClass().getSuperclass()));

	protected List<T> find(Object... paras) {
		List<T> result = t.find(getSqlPara(paras));
		return result;
	}

	protected List<T> find(Map data) {
		List<T> result = t.find(getSqlPara(data));
		return result;
	}

	protected T findFirst(Object... paras) {
		return t.findFirst(getSqlPara(paras));
	}

	protected T findFirst(Map data) {
		return t.findFirst(getSqlPara(data));
	}

	public T findById(Object idValue) {
		return this.t.findById(idValue);
	}

	public T findById(Object... idValues) {
		return this.t.findById(idValues);
	}

	public T findByIdLoadColumns(Object idValue, String columns) {
		return this.t.findByIdLoadColumns(idValue, columns);
	}

	public T findByIdLoadColumns(Object[] idValues, String columns) {
		return this.t.findByIdLoadColumns(idValues, columns);
	}

	protected List<T> findByCache(String cacheName, Object key, Object... paras) {
		ICache cache = DbKit.getConfig(this.t.getClass()).getCache();
		List<T> result = cache.get(cacheName, key);
		if (result == null) {
			result = find(paras);
			cache.put(cacheName, key, result);
		}
		return result;
	}

	protected T findFirstByCache(String cacheName, Object key, Object... paras) {
		ICache cache = DbKit.getConfig(this.t.getClass()).getCache();
		T result = cache.get(cacheName, key);
		if (result == null) {
			result = findFirst(paras);
			cache.put(cacheName, key, result);
		}
		return result;
	}

	protected List<T> findByCache(String cacheName, Object key, Map data) {
		ICache cache = DbKit.getConfig(this.t.getClass()).getCache();
		List<T> result = cache.get(cacheName, key);
		if (result == null) {
			result = find(data);
			cache.put(cacheName, key, result);
		}
		return result;
	}

	protected T findFirstByCache(String cacheName, Object key, Map data) {
		ICache cache = DbKit.getConfig(this.t.getClass()).getCache();
		T result = cache.get(cacheName, key);
		if (result == null) {
			result = findFirst(data);
			cache.put(cacheName, key, result);
		}
		return result;
	}

	protected Page<T> paginate(int pageNumber, int pageSize, Object... paras) {
		return this.t.paginate(pageNumber, pageSize, getSqlPara(paras));
	}

	protected Page<T> paginate(int pageNumber, int pageSize, Map data) {
		return this.t.paginate(pageNumber, pageSize, getSqlPara(data));
	}

	protected Page<T> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, Object... paras) {
		ICache cache = DbKit.getConfig(this.t.getClass()).getCache();
		Page<T> result = cache.get(cacheName, key);
		if (result == null) {
			result = paginate(pageNumber, pageSize, paras);
			cache.put(cacheName, key, result);
		}
		return result;
	}

	protected Page<T> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, Map data) {
		ICache cache = DbKit.getConfig(this.t.getClass()).getCache();
		Page<T> result = cache.get(cacheName, key);
		if (result == null) {
			result = paginate(pageNumber, pageSize, data);
			cache.put(cacheName, key, result);
		}
		return result;
	}

	protected SqlPara getSqlPara(Object... paras) {
		return this.t.getSqlPara(getsqlKey(), paras);
	}

	protected SqlPara getSqlPara(Map data) {
		return this.t.getSqlPara(getsqlKey(), data);
	}

	public boolean deleteById(Object idValue) {
		return this.t.deleteById(idValue);
	}

	public boolean deleteById(Object... idValues) {
		return this.t.deleteById(idValues);
	}

	public List<T> findAll() {
		return this.t.findAll();
	}

	public boolean save(T t) {
		t.put("addpersonid", PlatFormContext.getCurrentUser().getUserid());
		t.put("addpersonname", PlatFormContext.getCurrentUser().getName());
		t.remove("modifypersonid");
		t.remove("modifypersonname");
		return t.save();
	}

	public boolean update(T t) {
		t.set("modifypersonid", PlatFormContext.getCurrentUser().getUserid());
		t.set("modifypersonname", PlatFormContext.getCurrentUser().getName());
		t.remove("addpersonid");
		t.remove("addpersonname");
		return t.update();
	}

	/**
	 * 获取sql模板的key,这里key的构成是Dao里面的packageName+className+"."+methodName
	 * 
	 * @return
	 */
	private String getsqlKey() {
		Class currentClass = getClass();
		// 不使用动态代理的情况也适用
		Class useFullClass = currentClass.getName().indexOf("$$EnhancerBy") == -1 ? currentClass
				: currentClass.getSuperclass();
		String className = useFullClass.getName();
		String methodName = "";
		StackTraceElement[] stacktraceItems = Thread.currentThread().getStackTrace();
		for (StackTraceElement item : stacktraceItems) {
			if (item.getClassName().equals(className)) {
				methodName = item.getMethodName();
				break;
			}
		}
		return className + "." + methodName;
	}
}
